あやしいAWSコンソールログインを監視するダッシュボードをSumoLogicで作ってみる
オペレーション部 江口です。
以前、SumoLogicで当社の基幹AWSアカウントのCloudTrailの情報を取得して可視化する、という紹介の記事を書きました。
上記記事では気になった部分について都度クエリを書きながら深掘りして調査していくところを紹介しています。ただ、実際の運用ではやはり問題をすぐ把握できるようダッシュボードを充実させたいところです。 SumoLogicはデフォルトのダッシュボードがかなり充実しているのが魅力の一つなのですが、今回は自分の目的に沿ってダッシュボードをカスタマイズすることに挑戦してみたいと思います。 目的は記事のタイトルのとおり、「あやしいAWSコンソールログインを監視する」です。
各パネルのクエリも紹介しておきますので、Sumoでのクエリの参考にもなれば幸いです(とはいえ私もまだSumoのクエリに慣れているわけではないので、あまり綺麗ではないかもしれませんが)。
作ったダッシュボード
まだ試行錯誤中ではありますが、現状では以下のような感じです。 せっかく可視化できるツールなのにほとんどテーブルなのがどうかと思いますが・・・
画像中にもコメントを入れてますが、それぞれのパネルについて以下解説します。
Logins from outsite Japan
日本以外からのアクセスについて情報を表示します。 当社は海外支社もありますし、海外出張中の社員のアクセスもあるので、海外からのアクセス=不審、というわけではもちろんありません。 とはいえ大部分の社員が日本にいるので、海外からのアクセス、その頻度を確認しておくことはそれなりに意義があります。
users
ユーザと国、ログインの成否の組み合わせをアクセスの多い順に表示します。
普段いるところではない地域からアクセスが試行されており、かつそのログインが失敗しているというのはかなり怪しいだろう・・・という想定で情報を出しています。
クエリは下記の通りです。| where country_code<>"JP" and !isNull(latitude)
という命令を削れば日本からのアクセスも集計の対象となります。
_sourceCategory = cloudtrail "ConsoleLogin" | parse "\"eventName\":\"*\"" as eventName nodrop | where eventName="ConsoleLogin" | json "sourceIPAddress" | parse "\"userName\":\"*\"" as user_name nodrop | json field=_raw "userIdentity.principalId" as principal_id nodrop | parse regex field = principal_id ":(?<user_principal>.+)" nodrop | if (user_name="", user_principal, user_name) as user | json field=_raw "responseElements.ConsoleLogin" as loginResult nodrop | parse "\"MFAUsed\":\"*\"" as mfaUsed nodrop | count by sourceIPAddress, user, loginresult | lookup latitude, longitude, country_code, country_name, region, city, postal_code from geo://location on ip = sourceIPAddress | where country_code<>"JP" and !isNull(latitude) | fields user, country_name, loginresult, _count | sort by _count, country_name asc, user, loginresult
contries
国別のアクセス数の集計です。 海外支社のない地域からのアクセスが多い場合は警戒する必要があります。 クエリは下記の通りです。こちらも| where country_code<>"JP" and !isNull(latitude)`という命令を削れば日本からのアクセスも集計の対象となります。
_sourceCategory = cloudtrail "ConsoleLogin" | parse "\"eventName\":\"*\"" as eventName nodrop | where eventName="ConsoleLogin" | json "sourceIPAddress" | parse "\"userName\":\"*\"" as user_name nodrop | json field=_raw "userIdentity.principalId" as principal_id nodrop | parse regex field = principal_id ":(?<user_principal>.+)" nodrop | if (user_name="", user_principal, user_name) as user | json field=_raw "responseElements.ConsoleLogin" as loginResult nodrop | parse "\"MFAUsed\":\"*\"" as mfaUsed nodrop | count by sourceIPAddress, user, loginresult | lookup latitude, longitude, country_code, country_name, region, city, postal_code from geo://location on ip = sourceIPAddress | where country_code<>"JP" and !isNull(latitude) | count by country_name | sort by _count
Non MFA User
当社ではAWSコンソールへのアクセスはMFAの利用を基本必須としているため、MFAを利用していないアカウントのアクセスは警戒する必要があります。 そのため、ソースIPアドレス、アクセスしてきている国、ログインの成否、アクセス回数を表示し、妥当なアクセスかを検討できるようにしました。 クエリは下記の通りです。
_sourceCategory = cm-core/cloudtrail "ConsoleLogin" | parse "\"eventName\":\"*\"" as eventName nodrop | where eventName="ConsoleLogin" | json "sourceIPAddress" | parse "\"userName\":\"*\"" as user_name nodrop | json field=_raw "userIdentity.principalId" as principal_id nodrop | parse regex field = principal_id ":(?<user_principal>.+)" nodrop | if (user_name="", user_principal, user_name) as user | json field=_raw "responseElements.ConsoleLogin" as loginResult nodrop | parse "\"MFAUsed\":\"*\"" as mfaUsed nodrop | where mfaUsed!="Yes" | lookup latitude, longitude, country_code, country_name, region, city, postal_code from geo://location on ip = sourceIPAddress| count by user_name,mfaUsed,sourceIPAddress,country_name,loginResult| sort by _count
Login from rare location
これはちょっとトリッキーな情報で、ユーザごとにアクセス元の国名を集計し、普段アクセスを行なっている国(期間中最もアクセスの多い国)と異なる国からのアクセスがあればその国名を表示します。クエリの都合上、アクセスの最も多い国と最も少ない国の2国のみ表示するため、3ヶ国以上からのアクセスがあった場合はこの2国以外の情報は出てきません。
「ふだんとは異なる環境からアクセスしているユーザ」を絞りこめる情報パネルは作れないかなあ・・・と試行錯誤した結果作りましたが、これで正解かというとちょっと自身がありません。理想は各ユーザごとに、ログインした国とそのアクセス数が表示されるのが理想なのですが、SumoLogicのクエリの統計コマンドでは、そこまで私では作りきれていません。 これは私がSumoLogicのクエリを完全に使いきれていないことに問題がある可能性があるため、まだ検討の余地がありそうです。 クエリは以下の通りです。
_sourceCategory = cloudtrail "ConsoleLogin" | parse "\"eventName\":\"*\"" as eventName nodrop | where eventName="ConsoleLogin" | json "sourceIPAddress" | parse "\"userName\":\"*\"" as user_name nodrop | json field=_raw "userIdentity.principalId" as principal_id nodrop | parse regex field = principal_id ":(?<user_principal>.+)" nodrop | if (user_name="", user_principal, user_name) as user | json field=_raw "responseElements.ConsoleLogin" as loginResult nodrop | parse "\"MFAUsed\":\"*\"" as mfaUsed nodrop | lookup latitude, longitude, country_code, country_name, region, city, postal_code from geo://location on ip = sourceIPAddress | withtime country_name | most_recent(country_name_withtime),least_recent(country_name_withtime) by user | where _mostrecent != _leastrecent
Failed login detail
エラーでアクセスに失敗している通信の詳細情報を表示します。この情報のみ、コンソールログイン以外も含めてあらゆるオペレーションのエラーの情報を表示しています。 これは前回の記事の終わりで見つけたような、不審なツールからの大量アクセスを捕捉できるような情報を抽出しています。クエリは以下の通りです。
_sourceCategory = cloudtrail | json "userAgent","errorCode" | json "userIdentity.userName" as userName| parse "\"eventName\":\"*\"" as event_name | parse regex field=event_name "^(?<event_type>[A-Z][a-z]+?)[A-Z]" | count by userName, userAgent, event_type,errorCode | where _count > 10 | sort _count
終わりに
とりあえず作ってみてはいるものの、普段とは違うアクセスであればGuardDutyでかなり検出してくれる気がするので、ここまでダッシュボードを作り込む意味があるかなあと思わないではないです。 とはいえこのパネルで出している情報のクエリはGuardDutyで検出したイベントの詳細の調査でも利用できるかもしれません。 社内有識者の意見も聞きつつ、情報をブラッシュアップできるといいなあと思っています。
以上、SumoLogicカスタムダッシュボードのご紹介でした。